using System;
using UnityEngine;

public class GameSession : Session
{
    public static GameSession Instance { get; } = new GameSession();

    public delegate void HandleFunc(NetPacket pck);
    private readonly HandleFunc[] m_handles =
        new HandleFunc[(int)GAME_OPCODE.CSMSG_COUNT];

    protected override void HandlePacket(NetPacket pck)
    {
        m_handles[pck.Opcode]?.Invoke(pck);
    }

    public void RegisterHandler(GAME_OPCODE opcode, HandleFunc handler)
    {
        m_handles[(int)opcode] = handler;
    }

    public void SendMmorpgLogin(UInt32 gsID, UInt32 acct, string token)
    {
        var pck = new NetPacket((int)GAME_OPCODE.CMSG_MMORPG_LOGIN);
        pck.Write(1);  // lang
        pck.Write("test");  // channel
        pck.Write("desktop");  // platform
        pck.Write(gsID);
        pck.Write(acct);
        pck.Write(token);
        PushSendPacket(pck);
    }

    public void SendCreateCharacter(string name)
    {
        var pck = new NetPacket((int)GAME_OPCODE.CMSG_CHARACTER_CREATE);
        pck.Write(name);
        pck.Write((uint)1);  // charTypeId
        pck.Write((byte)1);  // career
        pck.Write((byte)1);  // gender
        PushSendPacket(pck);
    }

    public void SendDeleteCharacter(uint playerID)
    {
        var pck = new NetPacket((int)GAME_OPCODE.CMSG_CHARACTER_DELETE);
        pck.Write(playerID);
        PushSendPacket(pck);
    }

    public void SendGetCharacterList()
    {
        var pck = new NetPacket((int)GAME_OPCODE.CMSG_CHARACTER_LIST);
        PushSendPacket(pck);
    }

    public void SendLoginCharacter(uint playerID)
    {
        var pck = new NetPacket((int)GAME_OPCODE.CMSG_CHARACTER_LOGIN);
        pck.Write(playerID);
        PushSendPacket(pck);
    }

    public void SendLoadMapFinish()
    {
        var pck = new NetPacket((int)GAME_OPCODE.CMSG_PLAYER_LOAD_MAP_FINISH);
        PushSendPacket(pck);
    }

    public void SendLocalTeleportFinish()
    {
        var pck = new NetPacket((int)GAME_OPCODE.CMSG_LOC_TELEPORT_FINISH);
        PushSendPacket(pck);
    }

    public void SendPlayerRevive()
    {
        var pck = new NetPacket((int)GAME_OPCODE.CMSG_PLAYER_REVIVE);
        PushSendPacket(pck);
    }

    public void SendSpellCast(UInt32 spellID, ObjGUID targetGuid, Vector3 selfPos, Vector3 selfDir)
    {
        var pck = new NetPacket((int)GAME_OPCODE.CMSG_SPELL_CAST);
        var pckEx = new NetPacketHelper(pck);
        pck.Write(spellID);
        pck.Write((UInt64)0);
        pckEx.Write(targetGuid);
        pckEx.Write(new Vector3(float.MaxValue, float.MaxValue, float.MaxValue));
        pckEx.Write(selfPos);
        pckEx.Write(selfDir);
        PushSendPacket(pck);
    }

    public void SendObjectInteractive(ObjGUID targetGuid, Vector3 selfPos, Vector3 selfDir)
    {
        var pck = new NetPacket((int)GAME_OPCODE.CMSG_OBJECT_INTERACTIVE);
        var pckEx = new NetPacketHelper(pck);
        pckEx.Write(targetGuid);
        pckEx.Write(selfPos);
        pckEx.Write(selfDir);
        PushSendPacket(pck);
    }
}

public class WaitGameSessionConnecting : CustomYieldInstruction
{
    public override bool keepWaiting
    {
        get
        {
            return GameSession.Instance.IsConnecting();
        }
    }
}

public class WaitGameSessionPacketResp : CustomYieldInstruction
{
    public NetPacket resp;
    public WaitGameSessionPacketResp(GAME_OPCODE opcode)
    {
        GameSession.Instance.RegisterHandler(opcode, pck => resp = pck);
    }
    public override bool keepWaiting
    {
        get
        {
            return GameSession.Instance.IsRunning() && resp == null;
        }
    }
}
